﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using HWmanagementDB;

namespace HWmanagementServer
{
    public class PersonMgr
    {
        //might need https
        //pass check, need to hash on client side for safe transfer
        public static bool checkLogin(string neptun, string PasswdHash)
        {
            using (Repository repo = new Repository())
            {
                //if no such user exists
                if (repo.UserRepository.GetByID(neptun) == null)
                {
                    //can't log on an unknown user
                    return false;
                }

                //getting the hash from the db using the user name
                var pass = repo.UserRepository.GetByID(neptun).PASSWD;
                
                //comparing them
                if (pass == PasswdHash)
                {
                    //logging the success
                    Program.log.LogDatabase(neptun, "Successful login!");
                    return true;
                }
                else
                {
                    //logging the failure
                    Program.log.LogDatabase(neptun, "Unsuccessful login attempt!");
                    return false;
                }
            }
        }

        public static UserModel getUserbyNeptun(string Neptun)
        {
            try
            {
                using (Repository repo = new Repository())
                {
                    //returns null if no such user exists    
                    return UserModel.fromDBTable(repo.UserRepository.GetByID(Neptun));
                }
            }
            catch
            {
                throw new Exception("Error while handling request!");
            }
        }

        //Getting the subjects of a user -- NOT TESTED!
        public static List<SubjectModel> getSubjects(string user)
        {
            List<SubjectModel> ret = new List<SubjectModel>();
            try
            {
                using (Repository repo = new Repository())
                {
                    //queriing the DB
                    IEnumerator<USER> UsrEnum = repo.UserRepository.Get
                        (
                            filter: (u) => u.NEPTUN == user,
                            properties: "SUBJECT"
                        ).GetEnumerator();
                    UsrEnum.MoveNext();
                    IEnumerator<SUBJECT> SubList = UsrEnum.Current.SUBJECT.GetEnumerator();
                    while (SubList.MoveNext())
                    {
                        ret.Add(SubjectModel.fromDBTable(SubList.Current));
                    }
                }

                return ret;
            }
            catch
            {
                throw new Exception("Error while handling request!");
            }
        }

        //view homework result -- NOT TESTED!
        public static ResultModel viewResult(int hwid, string user)
        {
            try
            {
                IEnumerator<RESULT> result;
                using (Repository repo = new Repository())
                {
                    //queriing the DB
                    result = repo.ResultRepository.Get
                        (
                        filter: (u) => (u.HOMEWORKID == hwid && (u.USERID == user))
                        ).GetEnumerator();

                    result.MoveNext();
                    return ResultModel.fromDBTable(result.Current);
                }
            }
            catch
            {
                throw new Exception("Error while handling request!");
            }

        }
    }

    public class TeacherMgr : PersonMgr
    {
        //Getting the files submitted for a homework by a student (only the latest version, or all versions)
        public static List<FileModel> getFiles(int hwid, string user, bool onlyLast)
        {
            try
            {
                List<FileModel> ret = new List<FileModel>();
                using (Repository repo = new Repository())
                {
                    IEnumerator<HOMEWORKDONE> hwds= repo.HomeworkdoneRepository.Get(filter: (hd) => hd.HOMEWORKID == hwid && hd.USERID == user,
                    order: (hd2) => hd2.OrderByDescending((hd3) => hd3.VERSION),properties: "FILE").GetEnumerator();

                    //adding the last version by default
                    hwds.MoveNext();
                    ret.Add(FileModel.fromDBTable(hwds.Current.FILE));

                    //if all versions are needed
                    if (onlyLast == false)
                    {
                        while(hwds.MoveNext())
                        {
                            ret.Add(FileModel.fromDBTable(hwds.Current.FILE));
                        }
                    }
                }
                return ret;
            }
            catch
            {
                throw new Exception("Error while handling request!");
            }
        }

        //Adding a new homework -- NOT TESTED!
        public static void postNewHomework(HomeworkModel hw, FileModel file)
        {
            try
            {
                using (Repository repo = new Repository())
                {   
                    //getting the last id from the file table
                    int fileid = 0;
                    try
                    {
                        IEnumerator<FILE> FileEnum = repo.FileRepository.Get
                            (
                            order: (u) => u.OrderByDescending((u2) => u2.ID)
                            ).GetEnumerator();

                        FileEnum.MoveNext();
                        fileid = FileEnum.Current.ID + 1;
                    }
                    catch (NullReferenceException)
                    {
                        //if null is returned by the query
                        fileid = 1;
                    }

                    file.id = fileid;
                    hw.fileid = fileid;

                    //getting the last hwid
                    int hwid = 0;
                    try
                    {
                        IEnumerator<HOMEWORK> HwEnum = repo.HomeworkRepository.Get
                            (
                            order: (u) => u.OrderByDescending((u2) => u2.ID)
                            ).GetEnumerator();

                        HwEnum.MoveNext();
                        hwid = HwEnum.Current.ID + 1;
                    }
                    catch (NullReferenceException)
                    {
                        //if null is returned by the query
                        hwid = 1;
                    }

                    hw.id = hwid;

                    //addig the file to the file table
                    repo.FileRepository.Insert(FileModel.toDBTable(file));

                    //Creating an empty group for the homework
                    //getting the last group id
                    int groupid = 0;
                    try
                    {
                        IEnumerator<GROUP> GroupEnum = repo.GroupRepository.Get
                            (
                            order: (u) => u.OrderByDescending((u2) => u2.ID)
                            ).GetEnumerator();

                        GroupEnum.MoveNext();
                        groupid = GroupEnum.Current.ID + 1;
                    }
                    catch (NullReferenceException)
                    {
                        //if null is returned by the query
                        groupid = 1;
                    }

                    //adding the new group
                    GROUP grp = new GROUP() { ID = groupid, COURSEID = hw.courseid };
                    repo.GroupRepository.Insert(grp);

                    //setting up the connection between the homework and the new group (doing it from one side is enough)
                    //if exception raises we might need to commit the new group before this
                    HOMEWORK hwdb = HomeworkModel.toDBTable(hw);
                    hwdb.GROUP.Add(grp);

                    //adding the homework to db
                    repo.HomeworkRepository.Insert(hwdb);

                    //logging (the userid is the teacher handing the homework out)
                    Program.log.LogDatabase(hw.userid, "A new homework was added with id of " + hw.id);
                    return;

                }
            }
            catch
            {
                Program.log.LogToFile("Error adding homework with id: " + hw.id);
                throw new Exception("Error while handling request!");
            }
        }

        //adding a new result -- NOT TESTED!
        public static void writeResult(ResultModel res)
        {
            try
            {
                using (Repository repo = new Repository())
                {
                    //getting the last result id
                    int resid = 0;
                    try
                    {
                        IEnumerator<RESULT> ResEnum = repo.ResultRepository.Get
                            (
                            order: (r) => r.OrderByDescending((r2) => r2.ID)
                            ).GetEnumerator();

                        ResEnum.MoveNext();
                        resid = ResEnum.Current.ID + 1;
                    }
                    catch (NullReferenceException)
                    {
                        //if null is returned by the query
                        resid = 1;
                    }

                    res.id = resid;
                    repo.ResultRepository.Insert(ResultModel.toDBTable(res));
                    //logging (the userid is the teacher handing the homework out)
                    Program.log.LogDatabase("OKTATO", "A new result was added to homework with id " + res.homeworkid + " for user " + res.userid);
                    return;
                }
            }
            catch
            {
                Program.log.LogToFile("Error adding result for hwid: " + res.homeworkid);
                throw new Exception("Error while handling request!");
            }
        }

        //adding a teacher to a subject -- TESTED, OK
        public static void addTeacher(string user, string subject)
        {
            try
            {
                using (Repository repo = new Repository())
                {
                    USER usr = repo.UserRepository.GetByID(user);
                    usr.SUBJECT.Add(repo.SubjectRepository.GetByID(subject));
                    repo.UserRepository.Update(usr);
                    //no need to do in on the subject table!

                    return;
                }
            }
            catch
            {
                Program.log.LogToFile("Error adding teacher " + user + " to subject " + subject + "!");
                throw new Exception("Error while handling request!");
            }
        }

        //removing a teacher from a subject -- TESTED, OK
        public static void removeTeacher(string user, string subject)
        {
            try
            {
                using (Repository repo = new Repository())
                {

                    USER usr = repo.UserRepository.GetByID(user);
                    usr.SUBJECT.Remove(repo.SubjectRepository.GetByID(subject));
                    repo.UserRepository.Update(usr);
                    //should we do this in the subject table as well?

                    return;
                }
            }
            catch
            {
                Program.log.LogToFile("Error removing teacher " + user + " from subject " + subject + "!");
                throw new Exception("Error while handling request!");
            }
        }

        //modifying an existing hw -- NOT TESTED!
        public static void modifyHomework(HomeworkModel hw)
        {
            try
            {
                using (Repository repo = new Repository())
                {
                    repo.HomeworkRepository.Update(HomeworkModel.toDBTable(hw));
                    return;
                }
            }
            catch
            {
                Program.log.LogToFile("Error modifying hw with id: " + hw.id + "!");
                throw new Exception("Error while handling request!");
            }
        }

        //modifying an existing result -- NOT TESTED!
        public static void modifyResult(ResultModel res)
        {
            try
            {
                using (Repository repo = new Repository())
                {
                    repo.ResultRepository.Update(ResultModel.toDBTable(res));
                    return;
                }
            }
            catch
            {
                Program.log.LogToFile("Error modifying result with hwid: " + res.homeworkid + "!");
                throw new Exception("Error while handling request!");
            }
        }

        //removing a homework -- NOT TESTED!
        public static void deleteHomework(int hwid)
        {
            try
            {
                using (Repository repo = new Repository())
                {
                    //first removing the group attached to the hw
                    //getting the group id
                    IEnumerator<HOMEWORK> hw = repo.HomeworkRepository.Get((h) => h.ID == hwid, properties: "GROUP").GetEnumerator();
                    hw.MoveNext();
                    int groupid = hw.Current.GROUP.ElementAt(0).ID;

                    //removing the group reference
                    hw.Current.GROUP.Clear();
                    //committing to the db
                    repo.HomeworkRepository.Update(hw.Current);

                    //removing the group
                    repo.GroupRepository.Delete(groupid);

                    //removing the hw
                    repo.HomeworkRepository.Delete(hwid);
                    return;
                }
            }
            catch
            {
                Program.log.LogToFile("Error removing homework with id: " + hwid + "!");
                throw new Exception("Error while handling request!");
            }
        }

        //getting the homeworks created by the teacher
        public static List<HomeworkModel> getTeacherHomeworks(string user, int courseId)
        {
            try
            {
                using (Repository repo = new Repository())
                {
                    List<HomeworkModel> ret = new List<HomeworkModel>();

                    IEnumerator<HOMEWORK> hws = repo.HomeworkRepository.Get(filter: (h) => h.COURSEID == courseId && h.USERID == user).GetEnumerator();

                    while (hws.MoveNext())
                    {
                        ret.Add(HomeworkModel.fromDBTable(hws.Current));
                    }

                    return ret;
                }
            }
            catch
            {
                Program.log.LogToFile("Error getting teacher homeworks!");
                throw new Exception("Error while handling request!");
            }
        }

        //getting the group id of the group for a homework
        public static int getGroupOnHw(int hwId)
        {
            try
            {
                using (Repository repo = new Repository())
                {
                    IEnumerator<HOMEWORK> hws = repo.HomeworkRepository.Get((h) => h.ID == hwId, properties: "GROUP").GetEnumerator();
                    hws.MoveNext();
                    return hws.Current.GROUP.ElementAt(0).ID;
                }
            }
            catch
            {
                Program.log.LogToFile("Error getting the group for a homewrok!");
                throw new Exception("Error while handling request!");
            }
        }

    }

    public class StudentMgr : PersonMgr
    {
        //Getting the students on a subject
        public static List<UserModel> getStudentsOnSubject(int subjId)
        {
            try
            {
                List<UserModel> ret = new List<UserModel>();
                using (Repository repo = new Repository())
                {
                    SUBJECT sub = repo.SubjectRepository.GetByID(subjId);
                    List<USER> usrs = sub.USER.ToList();
                    foreach (USER usr in usrs)
                    {
                        if (usr.RANK == 2)
                        {
                            ret.Add(UserModel.fromDBTable(usr));
                        }
                    }
                }
                return ret;
            }
            catch
            {
                //something went wrong
                throw new Exception("Error while handling request!");
            }
        }

        //Getting the users on a homework (only one group per hw)
        public static List<UserModel> getUsersOnHw(int hwid)
        {
            try
            {
                List<UserModel> ret = new List<UserModel>();
                using (Repository repo = new Repository())
                {
                    //getting the group for the hw (could be more, but we only use one as specified)
                    List<GROUP> grp = repo.HomeworkRepository.GetByID(hwid).GROUP.ToList();
                    GROUP g = grp.ElementAt(0);
                    //getting all users, with a navigabla group
                    IEnumerator<USER> users = repo.UserRepository.Get(properties: "GROUP").GetEnumerator();
                    //filtering the users by the group
                    while (users.MoveNext())
                    {
                        if (users.Current.GROUP.Contains(g))
                        {
                            ret.Add(UserModel.fromDBTable(users.Current));
                        }
                    }
                }
                return ret;
            }
            catch
            {
                //something went wrong
                throw new Exception("Error while handling request!");
            }
        }

        //Submit a homework by id -- NOT TESTED!
        public static void PostHomework(int hwid, string user, FileModel file)
        {
            try
            {
                //inserting to the the database
                using (Repository repo = new Repository())
                {
                    int version = 1;
                    //queriing the last version
                    try
                    {
                        IEnumerator<HOMEWORKDONE> HWDEnum = repo.HomeworkdoneRepository.Get
                            (
                            filter: (u) => u.USERID == user && u.HOMEWORKID == hwid,
                            order: (u) => u.OrderByDescending((u2) => u2.VERSION)
                            ).GetEnumerator();

                        HWDEnum.MoveNext();
                        version = HWDEnum.Current.VERSION + 1;
                    }
                    catch (NullReferenceException)
                    {
                        //if null is returned by the query
                        version = 1;
                    }

                    //queriing the id
                    int id = 1;
                    try
                    {
                        IEnumerator<HOMEWORKDONE> HWDEnum = repo.HomeworkdoneRepository.Get
                            (
                            order: (u) => u.OrderByDescending((u2) => u2.ID)
                            ).GetEnumerator();

                        HWDEnum.MoveNext();
                        id = HWDEnum.Current.ID + 1;
                    }
                    catch (NullReferenceException)
                    {
                        //if null is returned by the query
                        id = 1;
                    }

                    //getting the last id from the file table
                    int fileid = 0;
                    try
                    {
                        IEnumerator<FILE> FileEnum = repo.FileRepository.Get
                            (
                            order: (u) => u.OrderByDescending((u2) => u2.ID)
                            ).GetEnumerator();

                        FileEnum.MoveNext();
                        fileid = FileEnum.Current.ID + 1;
                    }
                    catch (NullReferenceException)
                    {
                        //if null is returned by the query
                        fileid = 1;
                    }
                    
                    file.id = fileid;

                    //addig the file to the file table
                    repo.FileRepository.Insert(FileModel.toDBTable(file));

                    //adding the homework to the homework table
                    HomeworkDoneModel hwd = new HomeworkDoneModel { id = id, userid = user, homeworkid = hwid, fileid = file.id, version = version };
                    repo.HomeworkdoneRepository.Insert(HomeworkDoneModel.toDBTable(hwd));

                    //logging
                    Program.log.LogDatabase(user, "Homework uploaded (hwid: " + hwid + ", fileid: " + file.id);
                    return;
                }
            }
            catch
            {
                //maybe we could log the error as well
                throw new Exception("Error while handling request!");
            }
        }

        //List homeworks -- NOT TESTED! 
        public static List<HomeworkModel> getStudentHomeworks(string user, int courseId)
        {
            try
            {
                List<HomeworkModel> ret = new List<HomeworkModel>();
                //queriing the database
                using (Repository repo = new Repository())
                {
                    //getting the groups the user is in
                    IEnumerator<GROUP> groups;
                    IEnumerator<USER> usrEnum;
                    usrEnum = repo.UserRepository.Get(filter: (u) => u.NEPTUN == user, properties: "GROUP").GetEnumerator();
                    usrEnum.MoveNext();
                    groups = usrEnum.Current.GROUP.GetEnumerator();

                    //filtering the groups by the courseid
                    while (groups.MoveNext())
                    {
                        if (groups.Current.COURSEID == courseId)
                        {
                            //query for each group
                            IEnumerator<GROUP> groupEnum;
                            groupEnum = repo.GroupRepository.Get
                            (
                                filter: (g) => g.ID == groups.Current.ID,
                                properties: "HOMEWORK"
                            ).GetEnumerator();
                            groupEnum.MoveNext();
                            IEnumerator<HOMEWORK> HwEnum = groupEnum.Current.HOMEWORK.GetEnumerator();
                            while (HwEnum.MoveNext())
                            {
                                ret.Add(HomeworkModel.fromDBTable(HwEnum.Current));
                            }
                        }
                    }

                }

                return ret;
            }
            catch (NullReferenceException)
            {
                //if no result is returned by the query
                throw new Exception("Error while handling request!");
            }
        }

        //Adding a student to a group -- NOT TESTED!
        public static void addStudentToGroup(string student, int group)
        {
            try
            {
                using (Repository repo = new Repository())
                {
                    USER usr = repo.UserRepository.GetByID(student);
                    usr.GROUP.Add(repo.GroupRepository.GetByID(group));
                    repo.UserRepository.Update(usr);
                    //no need to do in on the subject table!

                    return;
                }
            }
            catch
            {
                Program.log.LogToFile("Error adding student " + student + " to group: " + group);
                throw new Exception("Error while handling request!");
            }
        }

        //Removing a student from a group -- NOT TESTED!
        public static void removeStudentFromGroup(string student, int group)
        {
            try
            {
                using (Repository repo = new Repository())
                {
                    USER usr = repo.UserRepository.GetByID(student);
                    usr.GROUP.Remove(repo.GroupRepository.GetByID(group));
                    repo.UserRepository.Update(usr);
                    return;
                }
            }
            catch
            {
                Program.log.LogToFile("Error removing student " + student + " from group: " + group);
                throw new Exception("Error while handling request!");
            }
        }

    }
}
